package com.facemox.controller;

import java.io.IOException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TimeZone;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.facemox.bean.EnvConfig;
import com.facemox.bean.FaceExecuteLog;
import com.facemox.bean.FaceInfo;
import com.facemox.bean.FaceLink;
import com.facemox.bean.FaceLinkExecuteLog;
import com.facemox.bean.GlobalParameter;
import com.facemox.bean.PermissionAuthentication;
import com.facemox.bean.Statistic;
import com.facemox.service.AuthorizationService;
import com.facemox.service.EnvConfigService;
import com.facemox.service.FaceInfoService;
import com.facemox.service.GlobalParameterService;
import com.facemox.service.LinkTestService;
import com.facemox.service.StatisticService;
import com.fasterxml.jackson.databind.ObjectMapper;

@SuppressWarnings("all")
@RestController
public class LinkTestController {

    @Autowired
    private LinkTestService linkTestService;

    @Autowired
    private FaceLink faceLink;

    @Autowired
    private FaceInfoService faceInfoService;

    @Autowired
    private AuthorizationService authorizationService;

    @Autowired
    private GlobalParameterService globalParameterService;

    @Autowired
    private FaceExecuteLog faceExecuteLog;

    @Autowired
    private StatisticService statisticService;

    @Autowired
    private Statistic statistic;

    @Autowired
    private FaceLinkExecuteLog faceLinkExecuteLog;

    @Autowired
    private EnvConfigService envConfigService;

    // 添加链路
    @RequestMapping("add_link")
    public int addLinkSequence(HttpServletRequest request) {
        
        Enumeration<String> linkList = request.getParameterNames();
        String linkName = null;
        String[] linkValue = null;
        Map map = new HashMap<String, Object>();
        // String linkDetail = null;
        while (linkList.hasMoreElements()) {
            linkName = linkList.nextElement();
            linkValue = request.getParameterValues(linkName);
            map.put(linkName, linkValue);
        }

        String[] link_name = (String[]) map.get("link_name");
        String[] link_detail = (String[]) map.get("link_detail");
        String[] link_nodes = (String[]) map.get("link_nodes");
        String[] link_names = (String[]) map.get("link_names");

        StringBuilder linkNodeStr = new StringBuilder();
        StringBuilder linkNameStr = new StringBuilder();

        if (null != link_nodes) {
            for (int i = 0; i < link_nodes.length; i++) {
                if (i == 0) {
                    linkNodeStr.append(link_nodes[i]);
                    linkNameStr.append(link_names[i]);
                } else {
                    linkNodeStr.append("➜" + link_nodes[i]);
                    linkNameStr.append("➜" + link_names[i]);
                }
            }
            faceLink.setLinkName(link_name[0]);
            faceLink.setLinkNodeSequence(linkNodeStr.toString());
            faceLink.setLinkNodeNameSequence(linkNameStr.toString());
            faceLink.setLinkDetail(link_detail[0]);
        }
        
        Integer linkId = 0;
        FaceLink tempfaceLink = null;
        String templinkId = request.getParameter("linkId");
        int effectLine = 0;
        
        if(!"undefined".equalsIgnoreCase(templinkId)) {
            linkId = Integer.valueOf(templinkId);
            faceLink.setLinkId(linkId);
            effectLine = linkTestService.updateLinkTest(faceLink);
        }else {
            faceLink.setLinkId(null);
            effectLine = linkTestService.addLinkTest(faceLink);
        }
        
        return effectLine;
    }

    // 获取链路列表，首次查询25条
    @RequestMapping("get_link_list")
    public List<FaceLink> getLinkList() {
        List<FaceLink> linkList = linkTestService.getLinkList();
        String temp = "";
        for (FaceLink faceLink : linkList) {
            int length = faceLink.getLinkDetail().length();
            if (30 < faceLink.getLinkDetail().length()) {
                temp = faceLink.getLinkDetail().substring(0, 30);
            } else {
                temp = faceLink.getLinkDetail().substring(0, faceLink.getLinkDetail().length());
            }
            faceLink.setLinkDetail((temp));
        }
        return linkList;
    };

    // 分页获取链路列表
    @RequestMapping("get_link_list_page")
    public List<FaceLink> getLinkListPage(HttpServletRequest request) {

        String pageSize = request.getParameter("pageSize");
        String fromPageStr = request.getParameter("fromPage");
        Integer fromPage = Integer.valueOf(fromPageStr);
        String toPageStr = request.getParameter("toPage");
        Integer toPage = Integer.valueOf(toPageStr);

        List<FaceLink> linkListPage = linkTestService.getLinkListPage(fromPage, toPage);

        String temp = "";
        for (FaceLink faceLink : linkListPage) {
            int length = faceLink.getLinkDetail().length();
            if (30 < faceLink.getLinkDetail().length()) {
                temp = faceLink.getLinkDetail().substring(0, 30);
            } else {
                temp = faceLink.getLinkDetail().substring(0, faceLink.getLinkDetail().length());
            }
            faceLink.setLinkDetail((temp));
        }
        return linkListPage;
    };

    // 获取链路总数
    @RequestMapping("get_link_list_count")
    public int getLinkListCount() {
        int totalCount = linkTestService.getLinkListCount();
        return totalCount;
    };

    // 根据链路ID查找链路
    @RequestMapping("find_link_by_id")
    public FaceLink findLinkById(HttpServletRequest request) {
        String templinkId = request.getParameter("link_id");
        Integer linkId = Integer.valueOf(templinkId);
        FaceLink faceLink = linkTestService.findLinkById(linkId);
        return faceLink;
    };

    // 根据链路ID删除链路
    @RequestMapping("delete_link_by_id")
    public int deleteLinkById(HttpServletRequest request) {
        String link_id = request.getParameter("link_id");
        int linkId = Integer.valueOf(link_id);

        int effectLine = linkTestService.deleteLinkById(linkId);

        return effectLine;
    }

    // 执行链路测试
    @RequestMapping("link_execute_by_id")
    public String link_execute_by_id(HttpServletRequest request)
            throws InterruptedException, ParseException, IOException, InstantiationException, IllegalAccessException {
        // 1、接受要执行的链路ID
        String templinkId = request.getParameter("link_id");
        Integer linkId = Integer.valueOf(templinkId);

        // 2、根据链路ID查询链路
        FaceLink faceLink = linkTestService.findLinkById(linkId);

        // 3、获取链路节点序列
        String linkNodeSequence = faceLink.getLinkNodeSequence();

        // 4、解析链路节点序列
        String[] LinkNodeArrs = linkNodeSequence.split("➜");

        StringBuilder requestResponseBody = new StringBuilder();
        String requestResponseBodyJson = null;
        String body = null;
        for (int i = 0; i < LinkNodeArrs.length; i++) {

            String linkNodeStr = LinkNodeArrs[i];
            Integer faceId = Integer.valueOf(linkNodeStr);

            // 5、根据FaceId查询接口相关信息
            FaceInfo face = faceInfoService.findFace(faceId);

            // 6、获取authenticationId
            Integer authenticationId = face.getAuthenticationId();

            // 获取ModuleId
            Integer moduleId = face.getModuleId();
            // 7、根据authID查询auth相关信息
            PermissionAuthentication auth = authorizationService.findAuthorizationByAuthenticationId(authenticationId);

           // 重构 Start

            CloseableHttpResponse response = null;
            HttpEntity responseEntity = null;
            String responseBody = null;
            CloseableHttpClient httpClient = HttpClients.createDefault();
            
            switch (auth.getAuthenticationType()) {
            case "no_auth":

                String host0 = getEnvConfigHost(face);

                String body0 = getGlobalParameter(face);

                StringEntity entity0 = setHttpEntity(body0);

                switch (face.getFaceMethod()) {
                case "POST":
                    HttpPost httpPost = new HttpPost("http://" + host0 + face.getFaceUrl());
                    httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPost.setEntity(entity0);
                    response = httpClient.execute(httpPost);
                    break;
                case "PUT":
                    HttpPut httpPut = new HttpPut("http://" + host0 + face.getFaceUrl());
                    httpPut.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPut.setEntity(entity0);
                    response = httpClient.execute(httpPut);
                    break;
                case "GET":
                    HttpGet httpGet = new HttpGet("http://" + host0 + face.getFaceUrl());
                    httpGet.setHeader("Content-Type", "application/json; charset=utf-8");
                    response = httpClient.execute(httpGet);
                    break;
                case "DELETE":
                    HttpDelete httpDelete = new HttpDelete("http://" + host0 + face.getFaceUrl());
                    httpDelete.setHeader("Content-Type", "application/json; charset=utf-8");
                    response = httpClient.execute(httpDelete);
                    break;
                default:
                    System.out.println("请求方法不存在，请确认后重试！");
                    break;
                }
                break;
            case "bearer_token":
                
                String host1 = getEnvConfigHost(face);

                String body1 = getGlobalParameter(face);

                StringEntity entity1 = setHttpEntity(body1);

                switch (face.getFaceMethod()) {
                case "POST":
                    HttpPost httpPost = new HttpPost("http://" + host1 + face.getFaceUrl());
                    httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPost.setHeader("Authorization", auth.getToken());
                    httpPost.setEntity(entity1);
                    response = httpClient.execute(httpPost);
                    break;
                case "PUT":
                    HttpPut httpPut = new HttpPut("http://" + host1 + face.getFaceUrl());
                    httpPut.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPut.setHeader("Authorization", auth.getToken());
                    httpPut.setEntity(entity1);
                    response = httpClient.execute(httpPut);
                    break;
                case "GET":
                    HttpGet httpGet = new HttpGet("http://" + host1 + face.getFaceUrl());
                    httpGet.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpGet.setHeader("Authorization", auth.getToken());
                    response = httpClient.execute(httpGet);
                    break;
                case "DELETE":
                    HttpDelete httpDelete = new HttpDelete("http://" + host1 + face.getFaceUrl());
                    httpDelete.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpDelete.setHeader("Authorization", auth.getToken());
                    response = httpClient.execute(httpDelete);
                    break;
                default:
                    System.out.println("请求方法不存在，请确认后重试！");
                    break;
                }

                break;
            case "basic_auth":

                CredentialsProvider provider = new BasicCredentialsProvider();
                UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(auth.getUsername(), auth.getPassword());
                provider.setCredentials(AuthScope.ANY, credentials);
                CloseableHttpClient basicHttpClient = HttpClients.custom().setDefaultCredentialsProvider(provider).build();
                

                String host2 = getEnvConfigHost(face);

                String body2 = getGlobalParameter(face);

                StringEntity entity2 = setHttpEntity(body2);

                switch (face.getFaceMethod()) {
                case "POST":
                    HttpPost httpPost = new HttpPost("http://" + host2 + face.getFaceUrl());
                    httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPost.setEntity(entity2);
                    response = basicHttpClient.execute(httpPost);
                    break;
                case "PUT":
                    HttpPut httpPut = new HttpPut("http://" + host2 + face.getFaceUrl());
                    httpPut.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPut.setEntity(entity2);
                    response = basicHttpClient.execute(httpPut);
                    break;
                case "GET":
                    HttpGet httpGet = new HttpGet("http://" + host2 + face.getFaceUrl());
                    httpGet.setHeader("Content-Type", "application/json; charset=utf-8");
                    response = basicHttpClient.execute(httpGet);
                    break;
                case "DELETE":
                    HttpDelete httpDelete = new HttpDelete("http://" + host2 + face.getFaceUrl());
                    httpDelete.setHeader("Content-Type", "application/json; charset=utf-8");
                    response = basicHttpClient.execute(httpDelete);
                    break;
                default:
                    System.out.println("请求方法不存在，请确认后重试！");
                    break;
                }
                break;
            case "oauth_authorization_code":
                System.out.println("暂不开放此权限");
                break;
            case "oauth_implicit":
                System.out.println("暂不开放此权限");
                break;
            case "oauth_password_credentials":
                break;
            case "oauth_client_credentials":
                String access_token = FaceExecuteController.class.newInstance()
                        .permissionAuthentication(auth.getAccessTokenUrl(), auth.getUsername(), auth.getPassword());

                String host = getEnvConfigHost(face);

                body = getGlobalParameter(face);

                StringEntity entity = setHttpEntity(body);

                switch (face.getFaceMethod()) {
                case "POST":
                    HttpPost httpPost = new HttpPost("http://" + host + face.getFaceUrl());
                    httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPost.setHeader("Authorization", access_token);
                    httpPost.setEntity(entity);
                    response = httpClient.execute(httpPost);
                    break;
                case "PUT":
                    HttpPut httpPut = new HttpPut("http://" + host + face.getFaceUrl());
                    httpPut.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpPut.setHeader("Authorization", access_token);
                    httpPut.setEntity(entity);
                    response = httpClient.execute(httpPut);
                    break;
                case "GET":
                    HttpGet httpGet = new HttpGet("http://" + host + face.getFaceUrl());
                    httpGet.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpGet.setHeader("Authorization", access_token);
                    response = httpClient.execute(httpGet);
                    break;
                case "DELETE":
                    HttpDelete httpDelete = new HttpDelete("http://" + host + face.getFaceUrl());
                    httpDelete.setHeader("Content-Type", "application/json; charset=utf-8");
                    httpDelete.setHeader("Authorization", access_token);
                    response = httpClient.execute(httpDelete);
                    break;
                default:
                    System.out.println("请求方法不存在，请确认后重试！");
                    break;
                }
                break;
            default:
                System.out.println("没有与之匹配的权限");
                break;
            }

            responseEntity = response.getEntity();
            responseBody = EntityUtils.toString(responseEntity, "UTF-8");

            // 接口执行日志统计
            faceExecuteLogStatistics(faceId, authenticationId, moduleId, auth, body, responseBody);
            
            // 18、接口执行次数统计
            statistic.setFaceId(faceId);
            statistic.setModuleId(face.getModuleId());
            statistic.setAuthenticationId(authenticationId);
            statisticService.addFaceStatisticItem(statistic);
            
            // 判断链路有几个节点，一个节点拼接完成数据直接返回，多个节点需要在节点数据前面添加逗号，以符合JSON格式
            if (i == 0) {
                requestResponseBodyJson = "\"RequestBody@" + face.getFaceName() + "\":" + body + "," + "\"ResponseBody@"
                        + face.getFaceName() + "\":" + responseBody;
            } else {
                requestResponseBodyJson = ",\"RequestBody@" + face.getFaceName() + "\":" + body + ","
                        + "\"ResponseBody@" + face.getFaceName() + "\":" + responseBody;
            }
            
            requestResponseBody.append(requestResponseBodyJson);

            Thread.sleep(2000);
        }
        String responseJson = "{" + requestResponseBody.toString() + "}";

        // 19、链路执行日志统计
        faceLinkExecuteLog.setLinkId(linkId);
        faceLinkExecuteLog.setLinkName(faceLink.getLinkName());
        faceLinkExecuteLog.setLinkRequestReponseBody(responseJson);
        faceLinkExecuteLog.setCreateTime(new Date());
        int addFaceLinkExecuteLog = linkTestService.addFaceLinkExecuteLog(faceLinkExecuteLog);

        // JSON格式化
        responseJson = jsonFormat(responseJson);
        
        return responseJson;
        
    }
    
    
    /**
     * @param responseBody
     * @return
     */
    private String jsonFormat(String responseBody) {
        // JSON格式化
        ObjectMapper mapper = new ObjectMapper();
        try {
            Object obj = mapper.readValue(responseBody, Object.class);
            responseBody = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseBody;
    }

    /**
     * @param faceId
     * @param authenticationId
     * @param moduleId
     * @param auth
     * @param body
     * @param responseBody
     */
    private void faceExecuteLogStatistics(Integer faceId, Integer authenticationId, Integer moduleId,
            PermissionAuthentication auth, String body, String responseBody) {
        // 接口执行日志统计
        faceExecuteLog.setFaceId(faceId);
        faceExecuteLog.setModuleId(moduleId);
        faceExecuteLog.setAuthenticationId(authenticationId);
        faceExecuteLog.setAuthenticationType(auth.getAuthenticationType());
        faceExecuteLog.setRequestBody(body);
        faceExecuteLog.setResponseBody(responseBody);
        faceExecuteLog.setCreateTime(new Date());

        statisticService.addFaceExecutelog(faceExecuteLog);
    }

    /**
     * @param body
     * @return
     */
    private StringEntity setHttpEntity(String body) {
        StringEntity entity = new StringEntity(body, Charset.forName("UTF-8"));
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        return entity;
    }

    /**
     * @param face
     * @return
     */
    private String getGlobalParameter(FaceInfo face) {
        // 全局参数调用开始
        GlobalParameter globalParameter = globalParameterService.getGlobalParameter();

        String paramBody = globalParameter.getParamBody();
        String body = face.getFaceBody().trim();
        if (paramBody != null) {

            // JSON转Map
            JSONObject parseObject = JSON.parseObject(paramBody);
            Iterator<String> it = parseObject.keySet().iterator();

            while (it.hasNext()) {
                String key = it.next().toString();
                String value = parseObject.get(key).toString();

                // 获取全局变量在请求体中引用了几次
                int fromIndex = 0;
                int count = 0;
                while (true) {
                    int index = body.indexOf("${" + key + "}", fromIndex);
                    if (-1 != index) {
                        fromIndex = index + 1;
                        count++;
                    } else {
                        break;
                    }
                }

                // 拼接全局变量
                for (int i = 0; i < count; i++) {
                    int indexOf = body.indexOf("${" + key + "}");
                    if (indexOf != -1) {
                        String before = body.substring(0, indexOf);
                        String after = body.substring(indexOf + key.length() + 3, body.length());
                        body = before + value + after;
                    }
                }

            }

        }

        // 建立系统变量Map
        Map<String, Object> sysVarMap = new HashMap<String, Object>();

        sysVarMap.put("_uuid", UUID.randomUUID());

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        // UTC 0时区时间
        sysVarMap.put("_current_time_utc", df.format(new Date()));

        df.setTimeZone(TimeZone.getDefault());
        // UTC格式的当前系统的默认时区时间，服务器在北京获取的就是UTC+8的时间
        sysVarMap.put("_current_time_utc_local", df.format(new Date()));

        // 本地日期+时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sysVarMap.put("_current_datetime", sdf.format(new Date()));

        // 本地日期
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        sysVarMap.put("_current_date", sdf1.format(new Date()));

        // 随机数字,从零到一亿之间的随机数字
        sysVarMap.put("_random_number", new Random(666).nextInt(100000000));

        Iterator<String> iterator = sysVarMap.keySet().iterator();

        while (iterator.hasNext()) {
            String key = iterator.next().toString();
            String value = sysVarMap.get(key).toString();

            // 获取系统变量在请求体中引用了几次
            int fromIndex = 0;
            int count = 0;
            for (int x = 0; x < sysVarMap.size(); x++) {
                while (true) {
                    int index = body.indexOf("${" + key + "}", fromIndex);
                    if (-1 != index) {
                        fromIndex = index + 1;
                        count++;
                    } else {
                        break;
                    }
                }
            }

            // 拼接系统变量
            for (int i = 0; i < count; i++) {
                int indexOf = body.indexOf("${" + key + "}");
                if (indexOf != -1) {
                    String before = body.substring(0, indexOf);
                    String after = body.substring(indexOf + key.length() + 3, body.length());
                    body = before + sysVarMap.get(key).toString() + after;
                }
            }

        }
        return body;
    }

    /**
     * @param face
     * @return
     */
    private String getEnvConfigHost(FaceInfo face) {
        // 根据FaceHost查询对应的IP:端口或者域名:端口
        EnvConfig envConfig = envConfigService.getEnvConfig();
        String envConfigParamBody = envConfig.getParamBody();

        Map<String, Object> map = new HashMap<String, Object>();
        if (envConfigParamBody != null) {
            map = JSON.parseObject(envConfigParamBody);
        }

        String host = null;

        for (String key : map.keySet()) {
            if (key.equalsIgnoreCase(face.getFaceHost())) {
                host = map.get(key).toString();
            }
        }
        return host;
    }
    
    
}
